package com.etong.frame.directive.impl.database;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.etong.frame.directive.DefaultDirective;
import com.etong.frame.directive.GroupConfig;
import com.etong.frame.directive.factory.DirectiveExecutor;
import com.etong.frame.directive.util.CommonStatus;

public abstract class DatabaseDirective extends DefaultDirective {
	public final static String DOT = ",";
	public final static String EQU = "=";
	public final static String QUO = "'";
	public final static String EMP = "";
	public final static String BLA = " ";

	public final static String SELECT = "select";
	public final static String UPDATE = "update";
	public final static String DELETE = "delete";
	public final static String INSERT = "insert";
	public final static String REPLACE = "replace";
	public final static String COUNT = "count";

	//
	public final static String KEY_OBJECTS = "objects";
	public final static String KEY_SELECTS = "selects";
	public final static String KEY_REPLACES = "replaces";
	public final static String KEY_UPDATES = "updates";
	public final static String KEY_INSERTS = "inserts";
	public final static String KEY_DELETES = "deletes";
	public final static String KEY_COUNT = "count";

	//
	public final static int BUILD_INSERT = 1;
	public final static int BUILD_UPDATE = 2;
	public final static int BUILD_REPLACE = 3;
	public final static int BUILD_SELECT = 4;
	public final static int BUILD_DELETE = 5;
	public final static int BUILD_VALID = 6;
	public final static int BUILD_COMMON = 7;
	public final static int BUILD_COUNT = 8;

	public void setExecutor(DirectiveExecutor executor) {
		this.executor = executor;
	}

	protected static final Logger logger = LoggerFactory
			.getLogger(DatabaseDirective.class);

	protected DirectiveExecutor executor;

	// 表字段列表
	private boolean needFields = true;
	private List<Field> tableFields = new ArrayList<Field>();

	// 模板Sql配置
	private Statement statement;

	// 变量列表
	private Map<String, Placeholder> placeholders = new HashMap<String, Placeholder>();

	@Override
	public CommonStatus execute(Map<String, Object> vars) {

		if (null == executor) {
			logger.error("No executor set");
			return execError;
		}
		return executor.execute(this, vars);
	}

	@Override
	public CommonStatus execute(Map<String, Object> vars,
			GroupConfig groupConfig) {
		if (null == executor) {
			logger.error("No executor set");
			return execError;
		}
		return executor.execute(this, vars, groupConfig);
	}

	/**
	 * @Title : buildVariable
	 * @Description :
	 * @params
	 * @param vars
	 * @return 设定文件
	 * @return boolean 返回类型
	 * @throws
	 */
	abstract protected CommonStatus buildVariable(Map<String, Object> vars);

	/**
	 * 创建一个新的实例 DatabaseDirective.
	 * 
	 * @param directiveConfig
	 */
	public DatabaseDirective(Statement directiveConfig) {
		super(directiveConfig);
		this.statement = (Statement) directiveConfig;

		String tableOp = statement.getTable_op();
		String defaultOutputName = KEY_OBJECTS;
		if (SELECT.equalsIgnoreCase(tableOp)) {
			statement.setTableOp(BUILD_SELECT);
			defaultOutputName = KEY_SELECTS;
		} else if (UPDATE.equalsIgnoreCase(tableOp)) {
			statement.setOutput_format(OutputFormat.INT);
			statement.setTableOp(BUILD_UPDATE);
			defaultOutputName = KEY_UPDATES;
		} else if (DELETE.equalsIgnoreCase(tableOp)) {
			statement.setOutput_format(OutputFormat.INT);
			statement.setTableOp(BUILD_DELETE);
			defaultOutputName = KEY_DELETES;
		} else if (REPLACE.equalsIgnoreCase(tableOp)) {
			statement.setOutput_format(OutputFormat.INT);
			statement.setTableOp(BUILD_REPLACE);
			defaultOutputName = KEY_REPLACES;
		} else if (INSERT.equalsIgnoreCase(tableOp)) {
			statement.setOutput_format(OutputFormat.INT);
			statement.setTableOp(BUILD_INSERT);
			defaultOutputName = KEY_INSERTS;
		} else if (COUNT.equalsIgnoreCase(tableOp)) {
			statement.setOutput_format(OutputFormat.INT);
			statement.setTableOp(BUILD_COUNT);
			defaultOutputName = KEY_COUNT;
		} else {
			statement.setTableOp(BUILD_COMMON);
		}

		// 设置默认的输出格式
		if (null == statement.getOutput_format()) {
			statement.setOutput_format(OutputFormat.LIST);
		}

		// 设置默认的输出名
		if (null == statement.getOutput_name()
				|| statement.getOuputName().isEmpty()) {
			statement.setOutput_name(defaultOutputName);
		}
	}

	public Map<String, Placeholder> getPlaceholders() {
		return placeholders;
	}

	public void setPlaceholders(Map<String, Placeholder> placeholders) {
		this.placeholders = placeholders;
	}

	public static List<Placeholder> createPlaceholders(String expr) {
		return createPlaceholders(expr, false);
	}

	public Statement getStatement() {
		return statement;
	}

	public void setStatement(Statement statement) {
		this.statement = statement;
	}

	public List<Field> getTableFields() {
		return tableFields;
	}

	public void setTableFields(List<Field> tableFields) {
		this.tableFields = tableFields;
	}

	public Placeholder getPlaceholder(String name) {
		return this.placeholders.get(name);
	}

	public void addPlaceholder(Placeholder placeholder) {
		this.placeholders.put(placeholder.getName(), placeholder);
	}

	public Integer getOutputFormat() {
		return statement.getOutput_format();
	}

	/**
	 * @Title : createPlaceholders
	 * @Description : 创建用于替换的变量
	 * @params
	 * @param expr
	 * @return 设定文件
	 * @return List<Placeholder> 返回类型
	 * @throws
	 */
	public static List<Placeholder> createPlaceholders(String expr,
			boolean required) {
		return PlaceholderCreator.createPlaceholders(expr, required);
	}

	/**
	 * @Title : initDirective
	 * @Description : 初始化指令
	 * @params
	 * @return 设定文件
	 * @return boolean 返回类型
	 * @throws
	 */
	@Override
	public final boolean initDirective() {

		Statement statement = getStatement();
		String tableOp = statement.getTable_op();
		String tableName = statement.getTable_name();
		String tableFields = statement.getTable_fields();

		if (null == tableOp || tableOp.isEmpty()) {
			logger.error("Table op is empty");
			return false;
		}

		if (null == tableName || tableName.isEmpty()) {
			logger.error("Table name is empty");
			return false;
		}

		if ((null == tableFields || tableFields.isEmpty()) && isNeedFields()) {
			logger.error("Table fields is empty");
			return false;
		}

		if (!buildConst(statement)) {
			logger.error("Build const expr error:" + tableOp);
			return false;
		}

		if (placeholders.size() > 0) {
			logger.info("Placeholders:" + JSON.toJSONString(placeholders));
		}

		return true;
	}

	/**
	 * @Title : buildDirective
	 * @Description : 组建指令
	 * @params
	 * @param vars
	 * @return 设定文件
	 * @return CommonStatus 返回类型
	 * @throws
	 */
	@Override
	public CommonStatus buildDirective(Map<String, Object> vars) {

		CommonStatus status = buildVariable(vars);
		if (!status.succeed()) {
			logger.error("Build variable error:" + vars);
			return status;
		}

		// 替换sql中的变量
		// TODO ：不支持同一个变量在列表出现两次
		String sql = (String) status.getObject();
		for (String name : getPlaceholders().keySet()) {
			Placeholder placeholder = getPlaceholder(name);
			if (placeholder.isRequired() && !vars.containsKey(name)) {
				logger.error("No param named:" + name);
				status.error(CommonStatus.DIRECTIVE_CREATE_ERROR,
						"No param named:" + name);
				return status;
			}

			String value = vars.get(name) + EMP;
			if (placeholder.isVarchar()) {
				value = QUO + value + QUO;
			}
			sql = sql.replace(placeholder.getPlaceholder(), value);
		}

		status.setObject(sql);

		logger.info("Build sql succeed:" + sql);

		return status;
	}

	/**
	 * @Title : buildConst
	 * @Description : 组建sql常量部分
	 * @params
	 * @param tableOp
	 * @return 设定文件
	 * @return boolean 返回类型
	 * @throws
	 */
	public boolean buildConst(Statement statement) {
		logger.info("Build default:" + getStatement().getName() + "->"
				+ getStatement().getCall_expr());
		return true;
	}

	/**
	 * @Title : isCompleteField
	 * @Description : 判断是否完整的字段
	 * @params
	 * @param fieldValue
	 * @return 设定文件
	 * @return boolean 返回类型
	 * @throws
	 */
	protected boolean isCompleteField(String fieldValue) {
		return (!(fieldValue.indexOf("(") >= 0 && fieldValue.indexOf(")") < 0) && !(fieldValue
				.indexOf("${") >= 0 && fieldValue.indexOf("}") < 0));
	}

	/**
	 * @Title : createTableField
	 * @Description : 创建表字段
	 * @params
	 * @param fieldExpr
	 * @return 设定文件
	 * @return Field 返回类型
	 * @throws
	 */
	public Field createTableField(String fieldExpr, int createType) {

		Field field = new Field();
		if (BUILD_INSERT == createType) {
			field.setName(fieldExpr);
			field.setPlaceholders(createPlaceholders(fieldExpr));
		} else if (BUILD_UPDATE == createType) {
			int findIndex = fieldExpr.indexOf(EQU);
			if (findIndex > 0) {
				String filedName = fieldExpr.substring(0, findIndex);
				field.setName(filedName);
				field.setPlaceholders(createPlaceholders(filedName));
				field.createValue(fieldExpr.substring(findIndex + 1));
			}
		}
		return field;
	}

	private int getIntValue(Map<String, Object> vars, String name, int def) {

		Object opage = vars.get(name);
		if (opage instanceof Integer) {
			return (Integer) opage;
		} else if (opage instanceof String) {
			try {
				return Integer.parseInt((String) opage);
			} catch (NumberFormatException e) {

			}
		}
		return def;
	}

	/**
	 * @Title : resovlePagination
	 * @Description : 处理分页
	 * @params
	 * @param vars
	 * @param sql
	 * @return 设定文件
	 * @return String 返回类型
	 * @throws
	 */
	protected String resovlePagination(Map<String, Object> vars, String sql) {

		if (sql.indexOf("limit") > 0 || sql.indexOf("LIMIT") > 0) {
			return sql;
		}

		if (vars.containsKey("page")) {
			int page = getIntValue(vars, "page", 0);
			int pageSize = getIntValue(vars, "page_size", 10);
			sql += " limit " + page * pageSize + "," + pageSize;
		}

		return sql;
	}

	/**
	 * @Title : resolveFieldsConfig
	 * @Description :
	 * @params
	 * @param fieldsConfig
	 * @return 设定文件
	 * @return List<String> 返回类型
	 * @throws
	 */
	public List<String> resolveFieldsConfig(String fieldsConfig) {
		List<String> fieldSplices = new ArrayList<String>();
		int dotIndex = 0;
		do {
			dotIndex = fieldsConfig.indexOf(DOT);
			String fieldExpr = fieldsConfig;
			if (dotIndex > 0) {
				fieldExpr = fieldsConfig.substring(0, dotIndex);
			}
			do {
				// 字段值中包括函数未结束
				if (!isCompleteField(fieldExpr)) {
					dotIndex = fieldsConfig.indexOf(DOT, dotIndex + 1);
					if (dotIndex > 0) {
						fieldExpr = fieldsConfig.substring(0, dotIndex);
					} else {
						fieldExpr = fieldsConfig;
					}
				}
			} while (!isCompleteField(fieldExpr));

			if (null != fieldExpr && !fieldExpr.isEmpty()) {
				fieldSplices.add(fieldExpr);
			}
			fieldsConfig = fieldsConfig.substring(dotIndex + 1).trim();
		} while (dotIndex >= 0);

		return fieldSplices;
	}

	// 将变量添加字典中，在组建sql的时候可以进行替换
	public void addPlaceholders(List<Placeholder> placeholders) {
		for (Placeholder placeholder : placeholders) {
			addPlaceholder(placeholder);
		}
	}

	public void addTableField(Field tableField) {
		tableFields.add(tableField);
	}

	protected void clear() {
		placeholders.clear();
		tableFields.clear();
	}

	public boolean isNeedFields() {
		return needFields;
	}

	public void setNeedFields(boolean needFields) {
		this.needFields = needFields;
	}
}
